/**
 * DragonBonesFactory Class
 *
 * A simplified implementation of the DragonBones factory for parsing
 * skeleton data and building armatures.
 */

import {
  DragonBonesData,
  ArmatureData,
  TextureAtlasData,
  DragonBonesFactory as IDragonBonesFactory,
  Armature,
} from "./types";
import { DragonBonesArmature } from "./DragonBonesArmature";
import { Logger } from "../../../utils/Logger";

export class DragonBonesFactory implements IDragonBonesFactory {
  public dragonBonesDataMap: Map<string, DragonBonesData> = new Map();
  public textureAtlasDataMap: Map<string, TextureAtlasData> = new Map();
  private textureMap: Map<string, any> = new Map(); // 存储已加载的纹理

  /**
   * Parses DragonBones data and stores it in the factory
   * @param data - The DragonBones data to parse
   * @param name - Optional name for the data
   */
  public parseDragonBonesData(data: DragonBonesData, name?: string): void {
    const logger = Logger.getInstance();
    const dataName = name || data.name || "default";

    logger.log(`Parsing DragonBones data: ${dataName}`, "DragonBonesFactory");

    if (!data.armature || data.armature.length === 0) {
      logger.warn(
        `No armatures found in DragonBones data: ${dataName}`,
        "DragonBonesFactory"
      );
      return;
    }

    this.dragonBonesDataMap.set(dataName, data);
    logger.log(
      `Successfully parsed DragonBones data with ${data.armature.length} armatures`,
      "DragonBonesFactory"
    );
  }

  /**
   * Parses texture atlas data and stores it in the factory
   * @param data - The texture atlas data to parse
   * @param name - Optional name for the data
   */
  public parseTextureAtlasData(data: TextureAtlasData, name?: string): void {
    const logger = Logger.getInstance();
    const dataName = name || "default";

    logger.log(`Parsing texture atlas data: ${dataName}`, "DragonBonesFactory");
    this.textureAtlasDataMap.set(dataName, data);
    logger.log(
      `Successfully parsed texture atlas data with ${data.SubTexture.length} textures`,
      "DragonBonesFactory"
    );
  }

  /**
   * Builds an armature from the parsed data
   * @param armatureName - The name of the armature to build
   * @param dragonBonesName - Optional name of the DragonBones data
   * @returns The built armature or null if not found
   */
  public buildArmature(
    armatureName: string,
    dragonBonesName?: string
  ): Armature | null {
    const logger = Logger.getInstance();
    logger.log(`Building armature: ${armatureName}`, "DragonBonesFactory");

    // Find the DragonBones data
    let dragonBonesData: DragonBonesData | undefined;
    if (dragonBonesName) {
      dragonBonesData = this.dragonBonesDataMap.get(dragonBonesName);
    } else {
      // If no specific name provided, try to find in any data
      for (const data of this.dragonBonesDataMap.values()) {
        if (data.armature.some((armature) => armature.name === armatureName)) {
          dragonBonesData = data;
          break;
        }
      }
    }

    if (!dragonBonesData) {
      logger.warn(
        `DragonBones data not found for armature: ${armatureName}`,
        "DragonBonesFactory"
      );
      return null;
    }

    // Find the armature data
    const armatureData = dragonBonesData.armature.find(
      (a) => a.name === armatureName
    );
    if (!armatureData) {
      logger.warn(
        `Armature data not found: ${armatureName}`,
        "DragonBonesFactory"
      );
      return null;
    }

    // Create the armature
    const armature = new DragonBonesArmature(armatureData, this);
    logger.log(
      `Successfully built armature: ${armatureName}`,
      "DragonBonesFactory"
    );
    return armature;
  }

  /**
   * Gets the names of all armatures in the specified DragonBones data
   * @param dragonBonesName - Optional name of the DragonBones data
   * @returns Array of armature names
   */
  public getArmatureNames(dragonBonesName?: string): string[] {
    const armatureNames: string[] = [];

    if (dragonBonesName) {
      const dragonBonesData = this.dragonBonesDataMap.get(dragonBonesName);
      if (dragonBonesData) {
        armatureNames.push(...dragonBonesData.armature.map((a) => a.name));
      }
    } else {
      // Get armature names from all DragonBones data
      for (const dragonBonesData of this.dragonBonesDataMap.values()) {
        armatureNames.push(...dragonBonesData.armature.map((a) => a.name));
      }
    }

    return armatureNames;
  }

  /**
   * Loads a texture and stores it for use by armatures
   * @param imagePath - Path to the texture image
   * @param texture - The loaded texture (Canvas Image)
   */
  public loadTexture(imagePath: string, texture: any): void {
    this.textureMap.set(imagePath, texture);
  }

  /**
   * Gets a loaded texture by image path
   * @param imagePath - Path to the texture image
   * @returns The loaded texture or null if not found
   */
  public getTexture(imagePath: string): any {
    return this.textureMap.get(imagePath) || null;
  }

  /**
   * Gets the texture atlas data
   * @param name - Name of the texture atlas
   * @returns The texture atlas data or null if not found
   */
  public getTextureAtlasData(name?: string): TextureAtlasData | null {
    const atlasName = name || "default";
    return this.textureAtlasDataMap.get(atlasName) || null;
  }
}
